package cn.zz.veggie.application.service;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

import org.springframework.stereotype.Service;

import cn.zz.comm.core.types.query.PageQuery;
import cn.zz.comm.core.types.result.PageResult;
import cn.zz.comm.helper.BizCommHelper;
import cn.zz.comm.util.CollUtil;
import cn.zz.comm.util.CollectorUtil;
import cn.zz.veggie.application.assembler.ShopQuoteAssembler;
import cn.zz.veggie.application.packer.ProductPacker;
import cn.zz.veggie.model.domain.Product;
import cn.zz.veggie.model.domain.Shop;
import cn.zz.veggie.model.domain.ShopQuote;
import cn.zz.veggie.model.query.ProductQuery;
import cn.zz.veggie.model.query.ShopQuoteQuery;
import cn.zz.veggie.persistence.repository.ProductRepository;
import cn.zz.veggie.persistence.repository.ShopQuoteRepository;
import cn.zz.veggie.persistence.repository.ShopRepository;
import cn.zz.veggie.web.types.dto.mgmt.quote.MgmtProductQuoteQueryDto;
import cn.zz.veggie.web.types.dto.mgmt.quote.MgmtShopQuoteQueryDto;
import cn.zz.veggie.web.types.dto.mgmt.quote.MgmtShopQuoteSaveDto;
import cn.zz.veggie.web.types.vo.mgmt.MgmtProductQuoteVo;
import cn.zz.veggie.web.types.vo.mgmt.quote.MgmtShopQuoteVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @author zhongq
 * @since 2024/7/28
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ShopQuoteAppService {

	private final ShopQuoteRepository shopQuoteRepository;
	private final ShopRepository shopRepository;
	private final ProductRepository productRepository;

	public PageResult<MgmtShopQuoteVo> mgmtGetQuotes(MgmtShopQuoteQueryDto dto, PageQuery page) {
		// product filter
		final List<Integer> filterProductIds = productRepository.findIdsByName(dto.getProductName());
		if (filterProductIds != null && filterProductIds.isEmpty()) {
			return PageResult.of(page, Collections.emptyList());
		}
		ShopQuoteQuery query = ShopQuoteAssembler.buildQuery(dto, filterProductIds);
		final List<ShopQuote> shopQuotes = shopQuoteRepository.findByQuery(query, page);
		final Set<Integer> shopIds = CollectorUtil.bws(shopQuotes, ShopQuote::getShopId);
		final Map<Integer, Shop> shopMap = shopRepository.findByIds(shopIds);
		final Set<Integer> productIds = CollectorUtil.bws(shopQuotes, ShopQuote::getProductId);
		final Map<Integer, Product> productMap = productRepository.findByIds(productIds);
		// pack
		final List<MgmtShopQuoteVo> vos = CollectorUtil.bwl(shopQuotes, quote -> {
			final Shop shop = shopMap.get(quote.getShopId());
			final Product product = productMap.get(quote.getProductId());
			return ShopQuoteAssembler.toMgmtShopQuoteVo(quote, shop, product);
		});
		return PageResult.of(page, vos);
	}

	public void mgmtChangeQuote(MgmtShopQuoteSaveDto dto) {
		final Integer productId = dto.getProductId();
		final Product product = productRepository.findById(productId);
		BizCommHelper.requireNoNull(product, productId);
		final Integer shopId = dto.getShopId();
		final Shop shop = shopRepository.findById(shopId);
		BizCommHelper.requireNoNull(shop, shopId);
		ShopQuote quote = shopQuoteRepository.findOne(ShopQuoteQuery.of(shopId, productId));
		quote = ShopQuoteAssembler.createOrUpdate(quote, dto);
		shopQuoteRepository.save(quote);
	}

	public List<MgmtProductQuoteVo> mgmtGetProductQuotes(MgmtProductQuoteQueryDto dto) {
		final ProductQuery productQuery = new ProductQuery();
		productQuery.names = dto.getProducts();
		final List<Product> products = productRepository.findByPage(productQuery, PageQuery.all());
		if (CollUtil.isEmpty(products)) {
			return Collections.emptyList();
		}
		final List<Integer> productIds = CollectorUtil.bwl(products, Product::getId);
		final Integer shopId = dto.getShopId();
		Map<Integer, ShopQuote> productQuote = shopQuoteRepository.findProductQuote(shopId, productIds);
		return CollectorUtil.bwl(products, product -> {
			final MgmtProductQuoteVo vo = new MgmtProductQuoteVo();
			vo.setProduct(ProductPacker.toHisProductVo(product));
			Integer price = Optional.of(product.getId()).map(productQuote::get).map(ShopQuote::getPrice)
					.orElseGet(product::getPrice);
			vo.setQuote(price);
			return vo;
		});
	}
}